use std::{
    collections::HashMap, sync::Arc,
    fs::{self},
};
use parking_lot::{Condvar, Mutex};
// use actix_session::Session;
use actix_web::{
    HttpRequest, HttpResponse, Responder,
    get, post,
    web::{self},
};
use base64::prelude::*;
use captcha_rs::CaptchaBuilder;
use chrono::Utc;
use jsonwebtoken::{Algorithm, DecodingKey, EncodingKey, Header, Validation};
use lazy_static::lazy_static;
use libsm::sm4::{self, Mode, error::Sm4Error};
use rsa::{RsaPrivateKey, pkcs8::DecodePrivateKey};
use serde::{Deserialize, Serialize};

use crate::{InfoResponse, ResponseCode};

// const SESSION_KEY_AUTH_CAPTCHA: &str = "SESSION_KEY_AUTH_CAPTCHA";
// pub const SESSION_KEY_TOKEN: &str = "SESSION_KEY_TOKEN";
pub const SM4_KEY: &str = "D12NkCxycXsHcNjb";
pub const SM4_IV: &str = "ihWAEd74BdH0iT6F";
pub const TOKEN_CLIENT_KEY: &str = "Authorization";
pub const REFRESH_TOKEN_KEY: &str = "RefreshToken";
// pub const REFRESH_TOKEN_SECRET_KEY: &str =
//     "auuD/bCJQZX6UnPHpI7TJ2tG0/mElIJb65qcecctxM7bRP/hMwItlus2xyylaR6sg0a9PIS1P8Eju9jTeOr1ag==";

// 记录
lazy_static! {
    pub static ref SHARE_GLOBAL_AREA_MUTEX_PAIR: Arc<(
        parking_lot::lock_api::Mutex<parking_lot::RawMutex, HashMap<String, String>>,
        Condvar
    )> = Arc::new((Mutex::new(HashMap::new()), Condvar::new()));

}

// 验证码过期时间：60s
const CAPTCHA_EXPIRE_SECS: i64 = 60;
// Access Token过期时间：1h
const ACCESS_TOKEN_EXPIRE_SECS: i64 = 3600;
// Refres Token过期时间：1d
const REFRESH_TOKEN_EXPIRE_SECS: i64 = 86400;

#[derive(Debug, Deserialize)]
pub struct AuthRequest {
    username: String,
    password: String,
    captcha: String,
}

#[derive(Debug, Deserialize)]
struct AdminConfig {
    username: String,
    password: String,
}

// 验证码
#[derive(Debug, Deserialize, Serialize)]
struct Captcha {
    value: String,
    expire_secs: i64,
}

// impl<'de> Deserialize<'de> for Captcha {
//     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
//     where
//         D: Deserializer<'de>,
//     {
//         // 自定义反序列化逻辑（如处理特殊字段或格式）
//         // 示例：根据字段存在性判断变体
//         let value = String::deserialize(deserializer)?;
//         let (value, secs) = value.split_once(":").unwrap();
//         let expire_secs: i64 = secs.parse().unwrap();
//         Ok(Captcha {
//             value: value.to_owned(),
//             expire_secs,
//         })
//     }
// }

// impl Serialize for Captcha {
//     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//     where
//         S: Serializer,
//     {
//         serializer.serialize_str(&format!("{}:{}", self.value, self.expire_secs))
//     }
// }

#[derive(Debug, Deserialize, Serialize)]
pub struct AuthClaims {
    pub value: String,
    pub exp: i64,
}

// impl<'de> Deserialize<'de> for Token {
//     fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
//     where
//         D: Deserializer<'de>,
//     {
//         // 自定义反序列化逻辑（如处理特殊字段或格式）
//         // 示例：根据字段存在性判断变体
//         let value = String::deserialize(deserializer)?;
//         let (value, secs) = value.split_once(":").unwrap();
//         let expire_secs: i64 = secs.parse().unwrap();
//         Ok(Token {
//             value: value.to_owned(),
//             expire_secs,
//         })
//     }
// }

// impl Serialize for Token {
//     fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
//     where
//         S: Serializer,
//     {
//         serializer.serialize_str(&format!("{}:{}", self.value, self.expire_secs))
//     }
// }

pub fn decrypt(key: String, iv: String, input: String) -> Result<Vec<u8>, Sm4Error> {
    let sm4 = sm4::Cipher::new(key.as_bytes(), Mode::Cbc).unwrap();
    let data = BASE64_STANDARD.decode(input).unwrap();
    // let decrypt = match sm4.decrypt(&[], &data, iv.as_bytes()) {
    //     Err(e) => {
    //         return Err("Decryption failed: {e}")
    //     },
    //     Ok(decrypt) => decrypt,
    // };
    sm4.decrypt(&[], &data, iv.as_bytes())
    // String::from_utf8_lossy(&decrypt).to_string()
}

#[allow(dead_code)]
pub fn encrypt(key: String, iv: String, input: String) -> Result<Vec<u8>, Sm4Error> {
    let sm4 = sm4::Cipher::new(key.as_bytes(), Mode::Cbc).unwrap();
    sm4.encrypt(&[], &input.as_bytes(), iv.as_bytes())
}

// openssl genrsa -out private_key_pkcs1.pem 2048
// openssl pkcs8 -topk8 -inform PEM -in private_key_pkcs1.pem -outform PEM -nocrypt -out private_key_pkcs8.pem
// openssl rsa -in private_key_pkcs8.pem -pubout -out public_key.pem
fn generate_public_key() -> &'static str {
    include_str!("../key/public_key.pem")
}

fn get_captcha() -> HashMap<String, String> {
    let captcha = CaptchaBuilder::new()
        .length(4)
        .width(130)
        .height(40)
        .dark_mode(false)
        .complexity(1) // min: 1, max: 10
        .compression(40) // min: 1, max: 99
        .build();

    let base_img = captcha.to_base64();
    // captcha:now
    log::debug!("auth_captcha_text: {}", captcha.text);

    let claims = AuthClaims {
        value: captcha.text,
        exp: Utc::now().timestamp() + CAPTCHA_EXPIRE_SECS,
    };
    let captcha_secret_key = include_str!("../key/captcha_secret_key.txt");
    let key = EncodingKey::from_secret(captcha_secret_key.as_bytes());
    let token = jsonwebtoken::encode(&Header::default(), &claims, &key).unwrap();
    let token = format!("Bearer {}", token);

    let mut data = HashMap::new();
    data.insert("captcha".to_owned(), base_img);
    data.insert("nonce".to_owned(), token.clone());

    log::debug!("nonce: {}", token);

    /*Mutex*/
    // {
    //     let &(ref lock, ref cvar) = &*SHARE_GLOBAL_AREA_MUTEX_PAIR.clone();
    //     let mut loc = lock.lock();
    //     // Acquired Lock: ReadWrite
    //     // 同步数据
    //     loc.insert(k, token);
    //     // 通知其他等待的线程
    //     cvar.notify_all();
    //     // Released Lock
    // }

    data
}

// fn get_fingerprint(req: HttpRequest) -> String {
//     let ua = req.headers()
//         .get("user-agent")
//         .and_then(|h| h.to_str().ok())
//         .unwrap_or("");
//     let ip = req.connection_info()
//         .realip_remote_addr()
//         .unwrap_or("");
//     format!("{}-{}", ip, ua)
// }

#[get("/captcha")]
pub async fn auth_captcha() -> web::Json<InfoResponse<HashMap<String, String>>> {
    web::Json(InfoResponse {
        message: "Data generated".to_owned(),
        code: ResponseCode::Success,
        data: Some(get_captcha()),
    })
}

// 获取验证码
// 获取公钥
#[get("/prelude")]
pub async fn auth_prelude() -> web::Json<InfoResponse<HashMap<String, String>>> {
    let mut data = get_captcha();
    data.insert("key".to_owned(), generate_public_key().to_owned());

    web::Json(InfoResponse {
        message: "Data generated".to_owned(),
        code: ResponseCode::Success,
        data: Some(data),
    })
}

fn decode_token(
    req: HttpRequest,
    header_key: &'static str,
) -> (Option<AuthClaims>, Option<HttpResponse>, Option<String>) {
    let token = req
        .headers()
        .get(header_key)
        .and_then(|h| h.to_str().ok())
        .and_then(|s| s.strip_prefix("Bearer "));

    let token = match token {
        Some(t) => t,
        None => {
            return (
                None,
                Some(HttpResponse::Unauthorized().body(format!("Missing {} Header", header_key))),
                Some(format!("Missing {} Header", header_key)),
            );
        }
    };

    // 验证码是否在内存中，避免利用历史token访问
    // token
    log::debug!("{}: {}", header_key, token);

    let secret_key = match header_key {
        "RefreshToken" => include_str!("../key/refresh_token_secret_key.txt"),
        "AccessToken" => include_str!("../key/access_token_secret_key.txt"),
        "Nonce" | _ => include_str!("../key/captcha_secret_key.txt"),
    };

    let validation = Validation::default();
    let secret_key = DecodingKey::from_secret(secret_key.as_bytes());

    match jsonwebtoken::decode::<AuthClaims>(token, &secret_key, &validation) {
        Ok(token_data) => {
            return (Some(token_data.claims), None, None);
        }
        Err(e) => {
            log::error!("{e}");
            let response = match e.kind() {
                jsonwebtoken::errors::ErrorKind::ExpiredSignature => {
                    format!("{} expired", header_key)
                }
                _ => format!("Invalid {}", header_key),
            };
            return (
                None,
                Some(HttpResponse::Forbidden().body(response.clone())),
                Some(response),
            );
        }
    }
}

// 登录
#[post("")]
// #[route("", method = "POST", method = "GET")]
pub async fn auth(
    info: web::Json<AuthRequest>,
    req: HttpRequest,
) -> web::Json<InfoResponse<HashMap<String, String>>> {
    // let captcha = session.get::<Captcha>(SESSION_KEY_AUTH_CAPTCHA).unwrap();
    let (claims, rsp, message) = decode_token(req, "Nonce");
    if rsp.is_some() {
        // 生成新的验证码
        return web::Json(InfoResponse {
            message: message.unwrap(),
            code: ResponseCode::Error,
            data: Some(get_captcha()),
        });
    }

    // 验证码是否正确
    if let Some(claims) = claims {
        log::debug!("captcha::captcha: {:?}", claims.value);
        if !info.captcha.trim().eq_ignore_ascii_case(&claims.value) {
            return web::Json(InfoResponse {
                message: "Captcha error".to_owned(),
                code: ResponseCode::Error,
                data: Some(get_captcha()),
            });
        }
    } else {
        return web::Json(InfoResponse {
            message: "Captcha error".to_owned(),
            code: ResponseCode::Error,
            data: Some(get_captcha()),
        });
    }

    let s = fs::read_to_string("./pmm.toml").unwrap();
    let admin: AdminConfig = toml::from_str(&s).unwrap();
    if info.username.eq_ignore_ascii_case(&admin.username) {
        // 验证密码
        let raw = match decrypt(
            SM4_KEY.to_owned(),
            SM4_IV.to_owned(),
            admin.password.clone(),
        ) {
            Err(e) => {
                return web::Json(InfoResponse {
                    message: format!("Password {e}"),
                    code: ResponseCode::Failed,
                    data: Some(get_captcha()),
                });
            }
            Ok(raw) => raw,
        };

        let ciphertext = BASE64_STANDARD.decode(info.password.clone()).unwrap();
        let pkcs8 = include_str!("../key/private_key_pkcs8.pem");
        let private_key = RsaPrivateKey::from_pkcs8_pem(&pkcs8).unwrap();

        let client_raw = match private_key.decrypt(rsa::pkcs1v15::Pkcs1v15Encrypt, &ciphertext) {
            Err(e) => {
                return web::Json(InfoResponse {
                    message: format!("Password {e}"),
                    code: ResponseCode::Failed,
                    data: Some(get_captcha()),
                });
            }
            Ok(client_raw) => client_raw,
        };

        if client_raw == raw {
            let mut data = HashMap::new();

            let claims = AuthClaims {
                value: info.username.clone(),
                exp: Utc::now().timestamp() + ACCESS_TOKEN_EXPIRE_SECS,
            };

            let refresh_claims = AuthClaims {
                value: info.username.clone(),
                exp: Utc::now().timestamp() + REFRESH_TOKEN_EXPIRE_SECS,
            };

            let secret_key = include_str!("../key/access_token_secret_key.txt");
            let key = EncodingKey::from_secret(secret_key.as_bytes());
            let access_token = jsonwebtoken::encode(&Header::default(), &claims, &key).unwrap();

            let secret_key = include_str!("../key/refresh_token_secret_key.txt");
            let key = EncodingKey::from_secret(secret_key.as_bytes());
            let refresh_token =
                jsonwebtoken::encode(&Header::default(), &refresh_claims, &key).unwrap();

            data.insert(
                "access_token".to_owned(),
                format!("Bearer {}", access_token),
            );
            data.insert(
                "refresh_token".to_owned(),
                format!("Bearer {}", refresh_token),
            );

            log::debug!("access_token: {}", access_token);
            log::debug!("refresh_token: {}", refresh_token);

            // RefreshToken绑定设备

            // 密码验证通过
            return web::Json(InfoResponse {
                message: "Authorization ok".to_owned(),
                code: ResponseCode::Success,
                data: Some(data),
            });
        }
    }

    web::Json(InfoResponse {
        message: "Username or Password is incorrect.".to_owned(),
        code: ResponseCode::Failed,
        data: Some(get_captcha()),
    })
}

// 生成新的accesstoken
pub fn generate_access_token(mut claims: AuthClaims) -> String {
    claims.exp = Utc::now().timestamp() + ACCESS_TOKEN_EXPIRE_SECS;
    let pkcs8 = include_str!("../key/private_key_pkcs8.pem");
    let key = EncodingKey::from_rsa_pem(pkcs8.as_ref()).unwrap();
    jsonwebtoken::encode(&Header::new(Algorithm::RS256), &claims, &key).unwrap()
}

// 获取access_token
#[post("/refresh_access_token")]
pub async fn refresh_access_token(req: HttpRequest) -> impl Responder {
    // 从 Header 提取 Token
    // let token = req
    //     .headers()
    //     .get(REFRESH_TOKEN_KEY)
    //     .and_then(|h| h.to_str().ok())
    //     .and_then(|s| s.strip_prefix("Bearer "));

    // let token = match token {
    //     Some(t) => t,
    //     None => {
    //         return HttpResponse::Unauthorized()
    //             .body(format!("Missing {} Header", REFRESH_TOKEN_KEY));
    //     }
    // };

    // // 验证 Token
    // let validation = Validation::default();
    // let refresh_token_secret_key = include_str!("../key/refresh_token_secret_key.txt");
    // let secret_key = DecodingKey::from_secret(refresh_token_secret_key.as_bytes());
    // match jsonwebtoken::decode::<AuthClaims>(token, &secret_key, &validation) {
    //     Ok(token_data) => {
    //         // // 将用户信息注入请求扩展
    //         // Box::pin(self.service.call(req))
    //         // return (true, None);
    //         return HttpResponse::Ok().body(generate_access_token(token_data.claims));
    //     }
    //     Err(e) => {
    //         log::error!("{e}");
    //         let response = match e.kind() {
    //             jsonwebtoken::errors::ErrorKind::ExpiredSignature => "Refresh-Token expired",
    //             _ => "Invalid Refresh-Token",
    //         };
    //         // Box::pin(async { Ok(response.into()) })
    //         return HttpResponse::Forbidden().body(response);
    //     }
    // }

    let (claims, rsp, _message) = decode_token(req, REFRESH_TOKEN_KEY);
    if let Some(rsp) = rsp {
        return rsp;
    }
    HttpResponse::Ok().body(generate_access_token(claims.unwrap()))
}
